There are a handful of data types treated in a specific way in PHP; consider the following examples:
Symbols are much like strings, in that they are Unicode character sequences. The primary difference is the intended semantics: symbols represent semantic identifiers as opposed to textual literal values. Symbols are case sensitive.
In the text format, symbols are delimited by single-quotes and use the same escape characters.
See Ion Symbols for more details about symbol representations and symbol tables, and our section on Symbols, Tables and Catalogs for a distilled read.
See the section on reals for an introduction.
<?php
$d = new ion\Decimal(123);
echo ion\serialize($d), " = ", $d->isInt() ? "int" : "noint", "\n";
// 123d0 = int
$d = new ion\Decimal("123.123");
echo ion\serialize($d), " = ", $d->isInt() ? "int" : "noint" ,"\n";
// 123.123 = noint
?>
See the official ION spec about real numbers and also Ion Float and Ion Decimals for more notes.
The blob
type allows embedding of arbitrary raw binary data. Ion treats such data as a single (though often very large) value. It does no processing of such data other than passing it through intact.
In the text format, blob
values are denoted as RFC 4648-compliant Base64 text within two pairs of curly braces.
{{ dHdvIHBhZGRpbmcgY2hhcmFjdGVycw== }}
The clob
type is similar to blob
in that it holds uninterpreted binary data. The difference is that the content is expected to be text, so we use a text notation that’s more readable than Base64.
{{ "This is a CLOB of text." }}
See the official ION specification on Blobs and Clobs.
Timestamps represent a specific moment in time, always include a local offset, and are capable of arbitrary precision.
Instances of ion\Timestamp are really just plain \DateTime
objects augmented with Stringable
and ION specific formatting.
<?=
new ion\Timestamp(
precision: ion\Timestamp\Precision::FracTZ,
)
// 2022-02-25T16:11:54.118+00:00
?>
<?=
new ion\Timestamp(
precision: ion\Timestamp\Precision::Day
)
// 2022-02-25T
?>
<?=
new ion\Timestamp(
precision: ion\Timestamp\Precision::MinTZ,
format: ion\Timestamp\Format::Min,
datetime: "2020-03-15T12:34",
timezone: new DateTimeZone("Europe/Vienna")
)
// 2020-03-15T12:34+01:00
?>
See also the official ION Timestamp specification.
NOTE:
The interfaceSerializable
has been deprecated in 8.1 and should be replaced with magic serialize methods.
<?php
class srlzbl implements \Serializable {
private $data = "foo";
public function serialize() {
return "bar";
}
public function unserialize($data) {
$this->data = $data;
}
}
$srlzbl = new srlzbl;
var_dump($srlzbl);
$srlzd = ion\serialize($srlzbl);
echo $srlzd;
/*
object(srlzbl)#4 (1) {
["data":"srlzbl":private]=>
string(3) "foo"
}
S::srlzbl::{{"bar"}}
*/
?>
Everything as expected so far, Serializable
return a string
, but since they cannot indicate whether it's a valid UTF-8 string
, a ion\Type::CLob or ion\Type::BLob, CLobs are assumed.
Unserialization does not offer any surprises, either:
<?php
var_dump(ion\unserialize($srlzd));
/*
object(srlzbl)#4 (1) {
["data":"srlzbl":private]=>
string(3) "bar"
}
*/
?>
Implementing serialization behavior with magic methods is the preferred way since 8.1:
<?php
class magic {
private string $foo = "foo";
function __serialize() : array {
return ["foo" => "bar"];
}
function __unserialize(array $data) : void {
foreach ($data as $k => $v)
$this->$k = $v;
}
}
$magic = new magic;
var_dump($magic);
$srlzd = ion\serialize($magic);
echo $srlzd;
/*
object(magic)#6 (1) {
["foo":"magic":private]=>
string(3) "foo"
}
O::magic::{foo:"bar"}
*/
?>
Again, unserialization yields the expected results:
<?php
var_dump(ion\unserialize($srlzd));
/*
object(magic)#7 (1) {
["foo":"magic":private]=>
string(3) "bar"
}
*/
?>
Customly serializable objects work like magic serializable objects, with custom names for the magic methods.
<?php
class custom {
private array $data;
function init(array $data) : void {
$this->data = $data;
}
function export() : array {
return $this->data;
}
}
$custom = new custom;
$custom->init(["foo" => "bar"]);
echo $srlzd = ion\serialize($custom);
/*
c::custom::{data:p::custom::{foo:"bar"}}
*/
?>
The above is actually the result of serializing a standard class backed PHP object, because we didn't implement any serialization primitives and did neither specify a custom method to call. So let's just do that:
<?php
$srlzr = new ion\Serializer\Serializer(callCustomSerialize: "export");
echo $srlzd = ion\serialize($custom, $srlzr);
/*
C::custom::{foo:"bar"}
*/
?>
Note how this output compares to the output of the standard magic serializable object.
Unserialization works as used to, except sepcifying thwe custom unserialization method to call:
<?php
$unsrlzr = new ion\Unserializer\Unserializer(callCustomUnserialize: "init");
var_dump(ion\unserialize($srlzd, $unsrlzr));
/*
object(custom)#10 (1) {
["data":"custom":private]=>
array(1) {
["foo"]=>
string(3) "bar"
}
}
*/
?>
An S-expression (or symbolic expression) is much like a list in that it’s an ordered collection of values. However, the notation aligns with Lisp syntax to connote use of application semantics like function calls or programming-language statements. As such, correct interpretation requires a higher-level context other than the raw Ion parser and data model.
In the text format, S-expressions are bounded by parentheses. S-expressions also allow unquoted operator symbols (in addition to the unquoted identifier symbols allowed everywhere), so commas are interpreted as values rather than element separators.
null.sexp // A null S-expression value
() // An empty expression value
(cons 1 2) // S-expression of three values
([hello][there]) // S-expression containing two lists
(a+-b) ( 'a' '+-' 'b' ) // Equivalent; three symbols
(a.b;) ( 'a' '.' 'b' ';') // Equivalent; four symbols
Although Ion S-expressions use a syntax similar to Lisp expressions, Ion does not define their interpretation or any semantics at all, beyond the pure sequence-of-values data model indicated above.